<template>
  <div class="component-upload-image">
    <el-upload
      :accept="fileType.join(',')"
      list-type="picture-card"
      :multiple="limit !== 1"
      :disabled="disabled"
      :headers="getUpHeaders()"
      :action="getUpfileUrl()"
      :file-list="fileList"
      :before-upload="beforeUpload"
      :limit="limit"
      :on-preview="handlePreview"
      :on-change="handleChange"
      :on-remove="handleRemove"
      :class="{ hide: limit !== 0 && fileList.length >= limit }"
    >
      <div style="position: relative">
        <i class="el-icon-plus"></i>
        <div class="customTip">
          <slot></slot>
        </div>
      </div>
    </el-upload>

    <!-- 上传提示 -->
    <div class="fz-12 color9 linh-20 pt-5" slot="tip" v-if="showTip">
      请上传
      <template v-if="fileSize">
        大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
      </template>
      <template v-if="fileType">
        格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
      </template>
      的文件
    </div>

    <!-- 裁剪组件 -->
    <ImgCropper
      v-if="cropper"
      ref="ImgCropper"
      :fileType="fileType"
      :fileSize="fileSize"
      :width="width"
      :height="height"
      :borderRadius="borderRadius"
      @success="cropperSuccess"
    />

    <ImageViewer
      v-if="dialogVisible"
      :zIndex="2999"
      :on-close="()=>{dialogVisible = false}"
      :url-list="[dialogImageUrl]"
    />
  </div>
</template>

<script>
import { getFilename } from "@/utils/index";
import ImgCropper from "./imgCropper";
import { getUpHeaders, getUpfileUrl } from "@/api/upload";
import ImageViewer from "element-ui/packages/image/src/image-viewer";

export default {
  components: {
    ImgCropper,
    ImageViewer,
  },
  props: {
    // 绑定图片 limit === 1 ? url : [url]
    value: {
      type: [String, Array],
      default: "",
    },
    // 是否禁用
    disabled: {
      type: Boolean,
      default: false,
    },
    // 图片数量限制 设置为0则不限制上传数量
    limit: {
      type: Number,
      default: 1,
    },
    // 文件类型, 例如 ['.png', '.jpg', '.jpeg']
    fileType: {
      type: Array,
      default: () => [".png", ".jpg", ".jpeg"],
    },
    // 大小限制(MB)
    fileSize: {
      type: Number,
      default: 5,
    },
    // 是否显示提示
    isShowTip: {
      type: Boolean,
      default: true,
    },
    // 图片宽度
    width: {
      type: Number,
      default: 148,
    },
    // 图片高度
    height: {
      type: Number,
      default: 148,
    },
    // 圆角
    borderRadius: {
      type: String,
      default: "",
    },
    // 是否需要裁剪
    cropper: {
      type: Boolean,
      default: false,
    },
  },
  computed: {
    // 是否显示提示
    showTip() {
      return this.isShowTip && (this.fileType || this.fileSize);
    },
  },
  data() {
    return {
      fileList: [],
      dialogVisible: false,
      dialogImageUrl: "",
    };
  },
  watch: {
    value: {
      handler(val) {
        if (val) {
          // 首先将值转为数组
          const list = Array.isArray(val) ? val : [val];
          // 然后将数组转为对象数组
          const urlList = this.fileList
            .filter((v) => v.status === "success")
            .map((v) => v.url);
          if (JSON.stringify(list) === JSON.stringify(urlList)) return;

          this.fileList = list.map((url) => {
            return {
              uid: Date.parse(new Date()),
              name: getFilename(url),
              url: url,
              status: "success",
            };
          });
        } else {
          this.fileList = [];
          return [];
        }
      },
      deep: true,
      immediate: true,
    },
  },

  methods: {
    getUpHeaders,
    getUpfileUrl,
    // 上传图片之前
    beforeUpload(file) {
      const that = this;

      const upfileScope = that.fileType.map(
        (v) => "image/" + v.replace(".", "")
      );
      const isImgType = upfileScope.includes(file.type);
      if (!isImgType) {
        that.$message.error(`请上传${that.fileType.join(" ")}格式的图片!`);
      }
      const isImgSize = file.size / 1024 / 1024 < that.fileSize;
      if (!isImgSize) {
        that.$message.error(`图片大小不能超过${that.fileSize}M!`);
      }

      // 需要裁剪-拦截上传
      const isCropper = !that.cropper;
      if (!isCropper) {
        that.$refs.ImgCropper.show();

        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = () => {
          that.$nextTick(() => {
            that.$refs.ImgCropper.options.img = reader.result;
          });
        };
      }
      return isImgType && isImgSize && isCropper;
    },

    // 预览
    handlePreview(file) {
      this.dialogImageUrl = file.url;
      this.dialogVisible = true;
    },
    // 文件列表变化
    handleChange(file, fileList) {
      this.fileList = fileList;
      if (file.status === "success") {
        // 上传完成
        this.fileList.forEach((v) => {
          if (v.response) {
            if (v.response && v.response.code === 200) {
              v.url = v.response.url; // 更新视图,替换为在线链接
            }
          }
        });
        this.upVmodel(); // 更新v-model
      } else if (file.status === "fail") {
        this.$modal.msgError("上传图片失败，请重试");
        this.$modal.closeLoading();
      }
    },
    // 删除图片
    handleRemove(file, fileList) {
      this.fileList = fileList;
      this.upVmodel(); // 更新v-model
    },
    // 裁剪并上传完成
    cropperSuccess(url) {
      this.fileList.push({
        uid: Date.parse(new Date()),
        name: getFilename(url),
        url: url,
        status: "success",
      });

      this.upVmodel(); // 更新v-model
    },
    // 更新父组件v-model
    upVmodel() {
      const successList = this.fileList.filter((v) => v.status === "success");
      const urlList = successList.map((v) => v.url);
      this.$emit(
        "input",
        this.limit === 1
          ? urlList.length
            ? urlList[urlList.length - 1]
            : ""
          : urlList
      );
      this.$emit("successList", successList); // 需要使用file文件等场景
    },
  },
};
</script>
<style scoped lang="scss">
.customTip {
  position: absolute;
  bottom: 10px;
  left: 0;
  line-height: 20px;
  font-size: 12px;
  width: 100%;
  text-align: center;
  color: #999;
}
// 控制上传按钮+号部分
::v-deep.hide .el-upload--picture-card {
  display: none;
}
// 去掉动画效果
::v-deep .el-list-enter-active,
::v-deep .el-list-leave-active {
  transition: all 0s;
}

::v-deep .el-list-enter,
.el-list-leave-active {
  opacity: 0;
  transform: translateY(0);
}
::v-deep .el-upload-list__item-status-label > i {
  position: absolute;
  top: 1px;
  left: 13px;
}
</style>
